#!/usr/bin/env python3

#  Unicorn - Embeddable Unicode Library
#  Copyright (c) 2021-2025 Railgun Labs, LLC - All Rights Reserved
#
#  All information contained herein is and remains the property of Railgun Labs.
#  The intellectual and technical concepts contained herein are proprietary to
#  Railgun Labs and may be covered by U.S. and Foreign Patents, patents in process,
#  and are protected by trade secret or copyright law.
#
#  This Python script is an amalgamation of multiple scripts. It is intended for
#  consumption, not development. As part of the amalgamation process the code
#  has been obfuscated. This includes the removal of comments and type hints.
#  You may not reverse engineer, decompile, disassemble, or otherwise attempt
#  to derive the source code or underlying structure of this script.
#
#  The original source code can be obtained by purchasing a license
#  from Railgun Labs at https://RailgunLabs.com/unicorn/license.

b='16.0.0'
from enum import IntEnum
from dataclasses import dataclass
class eV(IntEnum):
 bk=32
 ej=16
 eI=8
 def c(self):
  return int(self/8)
@dataclass
class fe:
 def __init__(self,source='',header='',fd='',size=0):
  self.source=source
  self.header=header
  self.fd=fd
  self.size=size
from typing import List,Dict,Any,Optional
from dataclasses import dataclass
eR=int
a=1114112
dD=128
@dataclass
class dE:
 name:str
 dP:eR
 d:eR
 def __hash__(self):
  return hash(self.name)
 def __eq__(self,dQ):
  if isinstance(dQ,dE):
   return self.name==dQ.name
  return False
def cH(e):
 return [int(fb,16) for fb in e.split()]
class dZ:
 def __init__(self,f):
  self.eB=[0]*f
 def __hash__(self):
  bl=5381
  for value in self.eB:
   bl^=hash(value)
  return bl
 def __eq__(self,dQ):
  if isinstance(dQ,dZ):
   if len(self.eB)!=len(dQ.eB):
    return False
   for dR in range(len(self.eB)):
    if self.eB[dR]!=dQ.eB[dR]:
     return False
   return True
  return False
class bm:
 def __init__(self,index,name,dS,ea):
  self.id=index
  self.g=name
  self.dS=dS
  self.ea=ea
class fc:
 def __init__(self):
  self.characters={}
  self.eJ={}
  self.dl=None
 def eU(self,property,dS,ea):
  if property not in self.eJ:
   self.eJ[property]=bm(len(self.eJ),property,dS,ea)
  return self.eJ[property].id
 def get(self,property):
  return self.eJ[property].id
 def h(self):
  self.dl=dZ(len(self.eJ))
  for eC in self.eJ.values():
   self.dl.eB[eC.id]=eC.dS
 def bn(self,fb):
  if fb in self.characters:
   return self.characters[fb]
  else:
   eo=dZ(len(self.eJ))
   for eC in self.eJ.values():
    eo.eB[eC.id]=eC.dS
   self.characters[fb]=eo
   return eo
 def set(self,fb,property,value):
  self.bn(fb).eB[property]=value
 def eb(self,fb,property,value):
  self.bn(fb).eB[property]|=value
def cL(fi,struct,function):
 if len(fi.eJ)==0:
  return fe()
 fi.h()
 ek={}
 assert fi.dl is not None
 ek[fi.dl]=0
 dm=0
 for eS,ev in fi.characters.items():
  if ev not in ek:
   ek[ev]=len(ek)
  if ek[ev]!=0:
   dm=max(dm,eS)
 cI=[]
 cJ=[]
 cK=[]
 eJ=sorted(fi.eJ.values(),key=lambda ep:ep.ea,reverse=True)
 for code in range(dm+1):
  if code%dD!=0:
   continue
  dT=[]
  for bo in range(code,code+dD):
   if bo in fi.characters:
    ev=fi.characters[bo]
    if ev in ek:
     dT+=[ek[ev]]
     continue
   dT+=[0]
  if dT in cK:
   cI+=[cK.index(dT)*dD]
  else:
   cI+=[len(cJ)]
   cJ+=dT
   cK+=[dT]
 size=0
 source=''
 source+=f'const struct {struct} *{function}(unichar cp)\n'
 source+='{\n'
 source+=f'    static const struct {struct} {function}_unicode_codepoints[] = {{\n'
 for eo in ek.keys():
  source+='        {'
  for eC in eJ:
   source+='{0}u,'.format(eo.eB[eC.id])
   size+=eC.ea.c()
  source+='},\n'
 source+='    };\n\n'
 source+=f'    static const uint16_t {function}_stage1_table[] = {{'
 for index,value in enumerate(cI):
  if index%8==0:
   source+='\n'
   source+='        '
  source+='%d, '%value
  size+=2
 source+='\n'
 source+='    };\n\n'
 source+=f'    static const uint16_t {function}_stage2_table[] = {{'
 for index,value in enumerate(cJ):
  if index%8==0:
   source+='\n'
   source+='        '
  source+='%d, '%value
  size+=2
 source+='\n'
 source+='    };\n\n'
 source+=f'    const struct {struct} *data = NULL;\n'
 source+='    if (cp > UNICHAR_C({0}))\n'.format(dm)
 source+='    {\n'
 source+='        data = &{0}_unicode_codepoints[0]; // code point out of range\n'.format(function)
 source+='    }\n'
 source+='    else\n'
 source+='    {\n'
 source+='        const uint16_t stage2_offset = {0}_stage1_table[cp >> UNICHAR_C({1})];\n'.format(function,dD.bit_length()-1)
 source+='        const uint16_t codepoint_index = {0}_stage2_table[stage2_offset + (cp & UNICHAR_C({1}))];\n'.format(function,dD-1)
 source+='        data = &{0}_unicode_codepoints[codepoint_index];\n'.format(function)
 source+='    }\n'
 source+='\n'
 source+='    return data;\n'
 source+='}\n\n'
 i={eV.eI:'uint8_t',eV.ej:'uint16_t',eV.bk:'uint32_t'}
 header=''
 header+=f'struct {struct} {{\n'
 for eC in eJ:
  header+=f'     {i[eC.ea]} {eC.g};\n'
 header+='};\n'
 header+=f'const struct {struct} *{function}(unichar cp);\n'
 return fe(source,header,'',size)
from typing import List,Set,Dict,Any,Optional,Tuple,cast
import sys
import enum
import json
import zipfile
import fnmatch
class dF(enum.Enum):
 bp=enum.auto()
 cM=enum.auto()
class er(enum.Enum):
 el=enum.auto()
 j=enum.auto()
class ec(enum.IntFlag):
 eD=enum.auto()
 cN=enum.auto()
 cO=enum.auto()
class ed(enum.IntFlag):
 eD=enum.auto()
 bq=enum.auto()
 br=enum.auto()
 bs=enum.auto()
class dG(enum.IntFlag):
 eD=enum.auto()
 bt=enum.auto()
 bu=enum.auto()
class ee(enum.IntFlag):
 eD=enum.auto()
 bv=enum.auto()
 bw=enum.auto()
 bx=enum.auto()
class ef(enum.IntFlag):
 eD=enum.auto()
 by=enum.auto()
 bz=enum.auto()
 bA=enum.auto()
class eY(enum.IntFlag):
 eD=enum.auto()
 bB=enum.auto()
 bC=enum.auto()
 bD=enum.auto()
 bE=enum.auto()
 bF=enum.auto()
 bG=enum.auto()
 bH=enum.auto()
 bI=enum.auto()
 bJ=enum.auto()
 bK=enum.auto()
 bL=enum.auto()
 bM=enum.auto()
 bN=enum.auto()
 bO=enum.auto()
 bP=enum.auto()
 bQ=enum.auto()
 bR=enum.auto()
 bS=enum.auto()
 bT=enum.auto()
 bU=enum.auto()
class k:
 def __init__(self):
  self.normalization=ec.eD
  self.dU=ed.eD
  self.dn=dG.eD
  self.segmentation=ef.eD
  self.compression=False
  self.collation=False
  self.bV=False
class fa:
 def __init__(self):
  self.endian=dF.cM if sys.byteorder=='big' else dF.bp
  self.bW=True
  self.cP='uint32_t'
  self.optimize=er.el
  self.bX=32
  self.do=[]
  self.dV=ee.eD
  self.algorithms=k()
  self.eW=eY.eD
 def l(self,fb):
  blocks=self.do
  cQ=0
  cR=len(blocks)-1
  while cQ<=cR:
   dp=(cR+cQ)//2
   if fb<blocks[dp].dP:
    cR=dp-1
   elif fb>blocks[dp].d:
    cQ=dp+1
   else:
    return False
  return True
 def m(self):
  if self.cP.find('64')>0:
   return 8
  return 4
def q(p):
 dH=[]
 for o in p.split('.'):
  dH.append(int(o))
 while len(dH)<2:
  dH.append(0)
 return (dH[0],dH[1])
def eQ(bY,bZ):
 bY.lower().lstrip('is').replace('_','').replace(' ','')
 bZ.lower().rstrip('is').replace('_','').replace(' ','')
 return bY==bZ
def t(fh,algorithms):
 if not isinstance(algorithms,Dict):
  print("error: expected object for 'algorithms'")
  sys.exit(1)
 for key,value in algorithms.items():
  if key=='normalization':
   if not isinstance(value,List):
    print("error: expected string list for 'normalization'")
    sys.exit(1)
   for ew in value:
    if not isinstance(ew,str):
     print("error: expected string list for 'normalization'")
     sys.exit(1)
    if ew.lower()=='nfc':
     fh.algorithms.normalization|=ec.cN
    elif ew.lower()=='nfd':
     fh.algorithms.normalization|=ec.cO
    else:
     print('warning: ignoring unknown normalization form: {0}'.format(ew))
  elif key=='normalizationQuickCheck':
   if not isinstance(value,bool):
    print("error: expected boolean value for 'normalizationQuickCheck'")
    sys.exit(1)
   fh.algorithms.bV=value
  elif key=='caseConversion':
   if not isinstance(value,List):
    print("error: expected string list for 'caseConversion'")
    sys.exit(1)
   for ex in value:
    if not isinstance(ex,str):
     print("error: expected string list for 'caseConversion'")
     sys.exit(1)
    if ex.lower()=='lower':
     fh.algorithms.dU|=ed.bq
    elif ex.lower()=='upper':
     fh.algorithms.dU|=ed.br
    elif ex.lower()=='title':
     fh.algorithms.dU|=ed.bs
    else:
     print('warning: ignoring unknown case conversion target: {0}'.format(ex))
  elif key=='caseFolding':
   if not isinstance(value,List):
    print("error: expected string list for 'caseFolding'")
    sys.exit(1)
   for ex in value:
    if not isinstance(ex,str):
     print("error: expected string list for 'caseFolding'")
     sys.exit(1)
    if ex.lower()=='default':
     fh.algorithms.dn|=dG.bt
    elif ex.lower()=='canonical':
     fh.algorithms.dn|=dG.bu
    else:
     print('warning: ignoring unknown case fold target: {0}'.format(ex))
  elif key=='segmentation':
   if not isinstance(value,List):
    print("error: expected string list for 'segmentation'")
    sys.exit(1)
   for ew in value:
    if not isinstance(ew,str):
     print("error: expected string list for 'segmentation'")
     sys.exit(1)
    if ew.lower()=='grapheme':
     fh.algorithms.segmentation|=ef.by
    elif ew.lower()=='word':
     fh.algorithms.segmentation|=ef.bz
    elif ew.lower()=='sentence':
     fh.algorithms.segmentation|=ef.bA
    else:
     print('warning: ignoring unknown segmentation form: {0}'.format(ew))
  elif key=='compression':
   if not isinstance(value,bool):
    print("error: expected boolean value for 'compression'")
    sys.exit(1)
   fh.algorithms.compression=value
  elif key=='collation':
   if not isinstance(value,bool):
    print("error: expected boolean value for 'collation'")
    sys.exit(1)
   fh.algorithms.collation=value
  else:
   print('warning: ignoring unknown algorithm: {0}'.format(key))
def parse(filename,ff):
 fh=fa()
 if filename is None:
  return fh
 try:
  ca=open(filename,'r',encoding='utf-8')
 except FileNotFoundError:
  print('error: file not found: {0}'.format(filename))
  sys.exit(1)
 fg=json.load(ca)
 ca.close()
 if 'version' not in fg:
  print('error: missing version: {0}'.format(filename))
  sys.exit(1)
 version=q(fg['version'])
 if version[0]<1:
  print('error: illegal version: {0}'.format(version))
  sys.exit(1)
 cb=set()
 file=ff.open('blocks.json')
 blocks=[dE(*block) for block in json.loads(file.read())['blocks']]
 file.close()
 for key,value in fg.items():
  if key=='version':
   continue
  elif key=='endian':
   if not isinstance(value,str):
    print("error: expected string value for 'endian'")
    sys.exit(1)
   if value.lower()=='little':
    fh.endian=dF.bp
   elif value.lower()=='big':
    fh.endian=dF.cM
   elif value.lower()=='native':
    pass
   else:
    print("warning: expected 'little' or 'big' for 'endian'")
  elif key=='optimizeFor':
   if not isinstance(value,str):
    print("error: expected string value for 'optimizeFor'")
    sys.exit(1)
   if value.lower()=='speed':
    fh.optimize=er.el
   elif value.lower()=='size':
    fh.optimize=er.j
   else:
    print("warning: expected 'speed' or 'size' for 'optimizeFor'")
  elif key=='hasStandardAllocators':
   if not isinstance(value,bool):
    print("error: expected boolean value for 'hasStandardAllocators'")
    sys.exit(1)
   fh.bW=value
  elif key=='characterStorage':
   if not isinstance(value,str) or len(value.strip())==0:
    print("error: expected string value for 'characterStorage'")
    sys.exit(1)
   fh.cP=value
  elif key=='stackBufferSize':
   if not isinstance(value,int) or value<1:
    print("error: expected a positive integer value for 'stackBufferSize'")
    sys.exit(1)
   cS=4
   if value<cS:
    print(f"warning: rounding up 'stackBufferSize' from {value} to {cS} (the minimum)")
    value=cS
   fh.bX=value
  elif key=='excludeCharacterBlocks':
   if not isinstance(value,List):
    print("error: expected string list for 'excludeCharacterBlocks'")
    sys.exit(1)
   for cc in value:
    if not isinstance(cc,str):
     print("error: expected string list for 'excludeCharacterBlocks'")
     sys.exit(1)
    for block in blocks:
     if fnmatch.fnmatch(block.name,cc):
      cb.add(block)
  elif key=='encodingForms':
   if not isinstance(value,List):
    print("error: expected string list for 'encodingForms'")
    sys.exit(1)
   for encoding in value:
    if not isinstance(encoding,str):
     print("error: expected string list for 'encodingForms'")
     sys.exit(1)
    if encoding.lower()=='utf-8':
     fh.dV|=ee.bv
    elif encoding.lower()=='utf-16':
     fh.dV|=ee.bw
    elif encoding.lower()=='utf-32':
     fh.dV|=ee.bx
    else:
     print("warning: expected 'utf-8' or 'utf-16' or 'utf-32' for 'encodingForms'")
  elif key=='characterProperties':
   if not isinstance(value,List):
    print("error: expected string list for 'characterProperties'")
    sys.exit(1)
   for eT in value:
    if not isinstance(eT,str):
     print("error: expected string list for 'characterProperties'")
     sys.exit(1)
    if eQ(eT,'Alphabetic'):
     fh.eW|=eY.bB
    elif eQ(eT,'Canonical_Combining_Class'):
     fh.eW|=eY.bC
    elif eQ(eT,'Dash'):
     fh.eW|=eY.bD
    elif eQ(eT,'Diacritic'):
     fh.eW|=eY.bE
    elif eQ(eT,'Extender'):
     fh.eW|=eY.bF
    elif eQ(eT,'General_Category'):
     fh.eW|=eY.bG
    elif eQ(eT,'Hex_Digit'):
     fh.eW|=eY.bH
    elif eQ(eT,'Ideographic'):
     fh.eW|=eY.bI
    elif eQ(eT,'Lowercase'):
     fh.eW|=eY.bJ
    elif eQ(eT,'Math'):
     fh.eW|=eY.bK
    elif eQ(eT,'Noncharacter_Code_Point'):
     fh.eW|=eY.bL
    elif eQ(eT,'Numeric_Value'):
     fh.eW|=eY.bM
    elif eQ(eT,'Quotation_Mark'):
     fh.eW|=eY.bN
    elif eQ(eT,'Simple_Lowercase_Mapping'):
     fh.eW|=eY.bO
    elif eQ(eT,'Simple_Uppercase_Mapping'):
     fh.eW|=eY.bP
    elif eQ(eT,'Simple_Titlecase_Mapping'):
     fh.eW|=eY.bQ
    elif eQ(eT,'Terminal_Punctuation'):
     fh.eW|=eY.bR
    elif eQ(eT,'Unified_Ideograph'):
     fh.eW|=eY.bS
    elif eQ(eT,'Uppercase'):
     fh.eW|=eY.bT
    elif eQ(eT,'White_Space'):
     fh.eW|=eY.bU
    else:
     print('warning: ignoring unknown character property: {0}'.format(eT))
  elif key=='algorithms':
   t(fh,value)
  else:
   print('warning: ignoring unknown feature: {0}'.format(key))
 for block in cb:
  fh.do.append(block)
 fh.do=sorted(fh.do,key=lambda ep:ep.dP)
 return fh
from typing import Set,Tuple,Type
import zipfile
class Feature(object):
 def __init__(self):
  self.dq=0
 def eP(self,fi):
  pass
 def eX(self,ff,fi,fh):
  return fe()
 def cT(self,ff,fi,fh):
  return fe()
 @staticmethod
 def eO():
  return set()
dW=('flags',0,eV.eI)
cd=1
u=2
v=4
ce=8
cf=16
from typing import Dict,Set,Type
import zipfile
import json
x=1
y=2
z=4
B=8
C=16
D=32
E=64
F=128
G=256
H=512
J=1024
K=2048
N=4096
O=8192
class P(Feature):
 def eP(self,fi):
  fi.eU('binary_properties',0,eV.ej)
 def eX(self,ff,fi,fh):
  fd='#define UNICORN_FEATURE_BINARY_PROPERTIES\n'
  return fe(fd=fd)
class eL(Feature):
 @staticmethod
 def eO():
  return set([P])
 def eK(self,ff,fi,Q,R,V):
  file=ff.open('binary_properties.json')
  fg=json.loads(file.read())
  mappings=fg[Q]
  file.close()
  binary_properties=fi.get('binary_properties')
  for fb in mappings.keys():
   fi.eb(int(fb,16),binary_properties,R)
  header='#define {0}\n'.format(V)
  return fe(fd=header)
class W(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isNoncharacterCodePoint',x,'UNICORN_FEATURE_NONCHARACTER_CODE_POINT')
class Y(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isAlphabetic',y,'UNICORN_FEATURE_ALPHABETIC')
class Z(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isLowercase',z,'UNICORN_FEATURE_LOWERCASE')
class aa(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isUppercase',B,'UNICORN_FEATURE_UPPERCASE')
class ab(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isHexDigit',C,'UNICORN_FEATURE_HEX_DIGIT')
class ac(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isWhiteSpace',D,'UNICORN_FEATURE_WHITE_SPACE')
class ad(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isMath',E,'UNICORN_FEATURE_MATH')
class ae(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isDash',F,'UNICORN_FEATURE_DASH')
class af(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isDiacritic',G,'UNICORN_FEATURE_DIACRITIC')
class ag(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isExtender',H,'UNICORN_FEATURE_EXTENDER')
class ah(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isIdeographic',J,'UNICORN_FEATURE_IDEOGRAPHIC')
class ai(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isQuotationMark',K,'UNICORN_FEATURE_QUOTATION_MARK')
class aj(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isUnifiedIdeograph',N,'UNICORN_FEATURE_UNIFIED_IDEOGRAPH')
class ak(eL):
 def eX(self,ff,fi,fh):
  return self.eK(ff,fi,'isTerminalPunctuation',O,'UNICORN_FEATURE_TERMINAL_PUNCTUATION')
from typing import Dict
import zipfile
import json
class am(Feature):
 def eP(self,fi):
  fi.eU('general_category',29,eV.eI)
 def eX(self,ff,fi,fh):
  file=ff.open('gc.json')
  fg=json.loads(file.read())
  characters=fg['characters']
  file.close()
  al=fi.get('general_category')
  for fb,value in characters.items():
   fi.set(int(fb,16),al,value)
  fd='#define UNICORN_FEATURE_GC\n'
  return fe(fd=fd)
from typing import Dict
import zipfile
import json
class ao(Feature):
 def eP(self,fi):
  fi.eU('numeric_value_offset',0,eV.eI)
 def eX(self,ff,fi,fh):
  file=ff.open('numeric_values.json')
  fg=json.loads(file.read())
  mappings=fg['mappings']
  source=fg['source']
  header=fg['header']
  size=fg['size']
  file.close()
  an=fi.get('numeric_value_offset')
  for fb,index in mappings.items():
   fi.set(int(fb,16),an,index)
  fd='#define UNICORN_FEATURE_NUMERIC_VALUE\n'
  return fe(source,header,fd,size)
from typing import List,Dict,Set,Type
import zipfile
import json
es={}
et=[0]
eG=fc()
dI=32768
ey=8191
class ch(Feature):
 @staticmethod
 def eO():
  return set([cU])
 def eP(self,_):
  (eG.eU('simple_lowercase_mapping',ey,eV.ej),)
 def eX(self,ff,_,eg):
  file=ff.open('simple_case_mappings.json')
  fg=json.loads(file.read())
  ap=fg['lowercase']
  file.close()
  cg=eG.get('simple_lowercase_mapping')
  for fb,value in ap.items():
   eS=int(fb,16)
   dJ=int(value,16)
   em=eS-dJ
   if abs(em)>ey:
    if dJ not in es:
     es[dJ]=len(et)
     et.append(dJ)
    eG.set(eS,cg,dI|es[dJ])
   else:
    eG.set(eS,cg,em+ey)
  fd='#define UNICORN_FEATURE_SIMPLE_LOWERCASE_MAPPINGS\n'
  return fe(fd=fd)
class cj(Feature):
 @staticmethod
 def eO():
  return set([cU])
 def eP(self,_):
  (eG.eU('simple_uppercase_mapping',ey,eV.ej),)
 def eX(self,ff,_,eg):
  file=ff.open('simple_case_mappings.json')
  fg=json.loads(file.read())
  aq=fg['uppercase']
  file.close()
  ci=eG.get('simple_uppercase_mapping')
  for fb,value in aq.items():
   eS=int(fb,16)
   dK=int(value,16)
   em=eS-dK
   if abs(em)>ey:
    if dK not in es:
     es[dK]=len(et)
     et.append(dK)
    eG.set(eS,ci,dI|es[dK])
   else:
    eG.set(eS,ci,em+ey)
  fd='#define UNICORN_FEATURE_SIMPLE_UPPERCASE_MAPPINGS\n'
  return fe(fd=fd)
class cl(Feature):
 @staticmethod
 def eO():
  return set([cU])
 def eP(self,_):
  (eG.eU('simple_titlecase_mapping',ey,eV.ej),)
 def eX(self,ff,_,eg):
  file=ff.open('simple_case_mappings.json')
  fg=json.loads(file.read())
  ar=fg['titlecase']
  file.close()
  ck=eG.get('simple_titlecase_mapping')
  for fb,value in ar.items():
   eS=int(fb,16)
   dL=int(value,16)
   em=eS-dL
   if abs(em)>ey:
    if dL not in es:
     es[dL]=len(et)
     et.append(dL)
    eG.set(eS,ck,dI|es[dL])
   else:
    eG.set(eS,ck,em+ey)
  fd='#define UNICORN_FEATURE_SIMPLE_TITLECASE_MAPPINGS\n'
  return fe(fd=fd)
class cU(Feature):
 def cT(self,ff,eg,dr):
  size=0
  source='const unichar unicorn_simple_case_mappings[] = {'
  for index,eS in enumerate(et):
   if index%4==0:
    source+='\n    '
   source+='UNICHAR_C(0x{:04X}), '.format(eS)
   size+=4
  source+='};\n\n'
  header=f'#define CASING_IN_TABLE(C) (((C) & (uint16_t){dI}) == (uint16_t){dI})\n'
  header+='#define GET_CASED_VALUE(C) ((C) & (uint16_t)0x3FFF)\n'
  header+=f'#define CASING_DIFF {ey}\n'
  header+='extern const unichar unicorn_simple_case_mappings[{0}];\n'.format(len(et))
  assert len(et)<65535,'cannot use unsigned 16-bit integer anymore'
  fg=cL(eG,'CharCaseData','unicorn_get_character_casing')
  source+=fg.source
  header+=fg.header
  size+=fg.size
  return fe(source,header,'',size)
from typing import Dict,Set,Type
import zipfile
import json
class cm(Feature):
 def eP(self,fi):
  fi.eU(*dW)
 def eX(self,ff,fi,fh):
  file=ff.open('special_case_mappings.json')
  fg=json.loads(file.read())
  source=fg['source']
  header=fg['header']
  size=fg['size']
  mappings=fg['characterFlags']
  file.close()
  dX=fi.get(dW[0])
  header+='#define IS_CASED {0}u\n'.format(u)
  header+='#define IS_CASE_IGNORABLE {0}u\n'.format(v)
  for fb,flags in mappings.items():
   fi.eb(int(fb,16),dX,flags)
  return fe(source=source,header=header,size=size)
class cn(Feature):
 @staticmethod
 def eO():
  return set([ch,cm])
 def eX(self,_,eg,dr):
  fd='#define UNICORN_FEATURE_LOWERCASE_CONVERT\n'
  return fe(fd=fd)
class at(Feature):
 @staticmethod
 def eO():
  return set([cj,cm])
 def eX(self,_,eg,dr):
  fd='#define UNICORN_FEATURE_UPPERCASE_CONVERT\n'
  return fe(fd=fd)
class au(Feature):
 @staticmethod
 def eO():
  return set([cl,co,dM,cn])
 def eX(self,_,eg,dr):
  fd='#define UNICORN_FEATURE_TITLECASE_CONVERT\n'
  return fe(fd=fd)
from typing import List,Set,Type,Tuple
import zipfile
import json
class cp(Feature):
 def eP(self,fi):
  fi.eU('full_casefold_mapping_offset',0,eV.ej)
  fi.eU(*dW)
 def eX(self,ff,fi,fh):
  file=ff.open('casefold.json')
  fg=json.loads(file.read())
  source=fg['source']
  header=fg['header']
  size=fg['size']
  av=fg['hasGreek']
  aw=fg['caseFoldings']
  ax=fg['changesWhenCasefolded']
  file.close()
  dX=fi.get(dW[0])
  ay=fi.get('full_casefold_mapping_offset')
  for fb in av:
   fi.eb(fb,dX,ce)
  for fb in ax:
   fi.eb(fb,dX,cf)
  for fb,offset in aw:
   fi.set(fb,ay,offset)
  header+='#define UNICORN_CHAR_NEEDS_NORMALIZATION {0}u\n'.format(ce)
  header+='#define UNICORN_CHAR_CHANGES_WHEN_CASEFOLDED {0}u\n'.format(cf)
  fd='#define UNICORN_FEATURE_CASEFOLD_DEFAULT\n'
  return fe(source,header,fd,size)
class az(Feature):
 @staticmethod
 def eO():
  return set([cp,ds])
 def eX(self,ff,fi,fh):
  fd='#define UNICORN_FEATURE_CASEFOLD_CANONICAL\n'
  return fe(fd=fd)
from typing import Dict
import zipfile
import json
class dM(Feature):
 def eP(self,fi):
  fi.eU('canonical_combining_class',0,eV.eI)
 def eX(self,ff,fi,fh):
  file=ff.open('ccc.json')
  mappings=json.loads(file.read())['ccc']
  file.close()
  aA=fi.get('canonical_combining_class')
  for fb,ccc in mappings.items():
   fi.set(int(fb,16),aA,ccc)
  fd='#define UNICORN_FEATURE_CCC\n'
  return fe(fd=fd)
from typing import Dict,Set,Type
import zipfile
import json
class aC(Feature):
 @staticmethod
 def eO():
  return set([dM])
 def eP(self,fi):
  fi.eU('quick_check_flags',0,eV.eI)
 def eX(self,ff,fi,_):
  file=ff.open('quickcheck.json')
  fg=json.loads(file.read())
  aB=fg['quickCheckNFC']
  file.close()
  cV=fi.get('quick_check_flags')
  for fb,cW in aB.items():
   fi.eb(int(fb,16),cV,cW<<4)
  fd='#define UNICORN_FEATURE_NFC_QUICK_CHECK\n'
  return fe(fd=fd)
class aE(Feature):
 @staticmethod
 def eO():
  return set([dM])
 def eP(self,fi):
  fi.eU('quick_check_flags',0,eV.eI)
 def eX(self,ff,fi,_):
  file=ff.open('quickcheck.json')
  fg=json.loads(file.read())
  aD=fg['quickCheckNFD']
  file.close()
  cV=fi.get('quick_check_flags')
  for fb,cW in aD.items():
   fi.eb(int(fb,16),cV,cW)
  fd='#define UNICORN_FEATURE_NFD_QUICK_CHECK\n'
  return fe(fd=fd)
from typing import List,Dict,Set,Type
import zipfile
import json
class ds(Feature):
 @staticmethod
 def eO():
  return set([dM,cq])
 def eP(self,fi):
  fi.eU('canonical_decomposition_mapping_offset',0,eV.ej)
 def eX(self,ff,fi,fh):
  aF=fi.get('canonical_decomposition_mapping_offset')
  file=ff.open('normalize.json')
  mappings=json.loads(file.read())['decompositions']
  file.close()
  cX={}
  eE=[0]
  decompositions={}
  for key,value in mappings.items():
   fb=int(key,16)
   mapping=cH(value)
   decompositions[fb]=mapping
   cY=''.join([chr(aG) for aG in mapping])
   if cY in cX:
    canonical_decomposition_mapping_offset=cX[cY]
   else:
    canonical_decomposition_mapping_offset=len(eE)
    cX[cY]=len(eE)
    if fh.optimize==er.el:
     eE.append(len(mapping))
     eE+=mapping
    else:
     eh=[]
     for eo in mapping:
      eh+=[int(cZ) for cZ in chr(eo).encode('utf8')]
     assert len(eh)<255
     eE.append(len(eh))
     eE+=eh
   fi.set(fb,aF,canonical_decomposition_mapping_offset)
  size=len(eE)
  if fh.optimize==er.el:
   size*=fh.m()
  dt=0
  du=0
  for fb,cr in decompositions.items():
   for fb in cr:
    dv=[fb]
    dN=0
    while dN<len(dv):
     cs=dv[dN]
     if cs not in decompositions:
      dN+=1
      continue
     dv[dN:dN+1]=decompositions[cs]
    eh=[]
    for eo in cr:
     eh+=[int(cZ) for cZ in chr(eo).encode('utf8')]
    du=max(du,len(dv))
    if fh.optimize==er.el:
     dt=du
    else:
     dt=max(dt,len(eh))
  if fh.optimize==er.el:
   source='const unichar uni_canonical_decomp_mappings[] = {'
   for index,eS in enumerate(eE):
    if index%8==0:
     source+='\n'
     source+='    '
    source+='UNICHAR_C(0x{:02X}), '.format(eS)
   source+='\n'
   source+='};\n\n'
  else:
   source='const uint8_t uni_canonical_decomp_mappings[] = {'
   for index,eS in enumerate(eE):
    if index%8==0:
     source+='\n'
     source+='    '
    source+='(uint8_t)0x{:02X}, '.format(eS)
   source+='\n'
   source+='};\n\n'
  if fh.optimize==er.el:
   header='extern const unichar uni_canonical_decomp_mappings[{0}];\n'.format(len(eE))
  else:
   header='extern const uint8_t uni_canonical_decomp_mappings[{0}];\n'.format(len(eE))
  header+='#define LONGEST_UNICHAR_DECOMPOSITION {0}\n'.format(du+1)
  header+='#define LONGEST_RAW_DECOMPOSITION {0}\n'.format(dt+1)
  fd='#define UNICORN_FEATURE_NFD\n'
  return fe(source,header,fd,size)
from typing import List,Set,Tuple,Type
import zipfile
import json
class aL(Feature):
 @staticmethod
 def eO():
  return set([ds])
 def eP(self,fi):
  fi.eU('canonical_composition_mapping_offset',0,eV.ej)
  fi.eU('canonical_composition_mapping_count',0,eV.eI)
  fi.eU(*dW)
 def eX(self,ff,fi,fh):
  file=ff.open('normalize.json')
  fg=json.loads(file.read())
  mappings=fg['compositionMappings']
  ct=fg['compositionPairs']
  file.close()
  aH=fi.get('canonical_composition_mapping_offset')
  aI=fi.get('canonical_composition_mapping_count')
  dX=fi.get(dW[0])
  for da in mappings:
   dP=da[0]
   offset=da[1]
   count=da[2]
   fi.set(dP,aH,offset)
   fi.set(dP,aI,count)
   fi.eb(dP,dX,cd)
  size=0
  source='const struct CanonicalCompositionPair uni_canonical_comp_pairs[] = {\n'
  for cu in ct:
   aJ=cu[0]
   aK=cu[1]
   source+='    {{ UNICHAR_C(0x{:04X}), UNICHAR_C(0x{:04X}) }},\n'.format(aJ,aK)
   size+=8
  source+='};\n\n'
  header='struct CanonicalCompositionPair\n'
  header+='{\n'
  header+='    unichar codepoint;\n'
  header+='    unichar composed_codepoint;\n'
  header+='};\n'
  header+='#define CHAR_IS_COMPOSABLE {0}u\n'.format(cd)
  header+='extern const struct CanonicalCompositionPair uni_canonical_comp_pairs[{0}];\n'.format(len(ct))
  header+='\n'
  fd='#define UNICORN_FEATURE_NFC\n'
  return fe(source,header,fd,size)
import zipfile
class aM(Feature):
 def eX(self,ff,fi,fh):
  fd='#define UNICORN_FEATURE_COMPRESSION\n'
  return fe(fd=fd)
from typing import List,Dict,Set,Type
import zipfile
import json
aN=1<<31
db=aN
cv=1<<30
cw=1<<29
cx=db
class CollationNode:
 def __init__(self):
  self.ev=0
  self.eF={}
  self.cy=0
  self.dY=0
  self.cz=0
 def cA(self,fb):
  if fb in self.eF:
   return self.eF[fb]
  eN=CollationNode()
  eN.ev=fb
  self.eF[fb]=eN
  return eN
 def cB(self,ez):
  eF=list(self.eF.values())
  eF=sorted(eF,key=lambda ep:ep.ev)
  if len(eF)>0:
   self.cy=len(ez)
   for dw in eF:
    dw.cz=len(ez)
    ez.append(dw)
   for dw in eF:
    dw.cB(ez)
 def aO(self):
  ez=[]
  self.cB(ez)
  return ez
class aV(Feature):
 @staticmethod
 def eO():
  return set([ds])
 def eP(self,fi):
  fi.eU('collation_subtype',0,eV.eI)
 def eX(self,ff,fi,fh):
  dO=[0]
  dx={}
  def cC(eu):
   nonlocal dO
   nonlocal dx
   dy=[]
   for dR,en in enumerate(eu):
    if dR<len(eu)-1:
     dy.append(en|cx)
    else:
     dy.append(en)
   dc=' '.join([str(en) for en in dy])
   if dc in dx:
    return dx[dc]
   else:
    dY=len(dO)
    for en in dy:
     dO.append(en)
    dx[dc]=dY
    return dY
  collation=fc()
  dd=collation.eU('value',0,eV.bk)
  file=ff.open('allkeys.json')
  fg=json.loads(file.read())
  aP=fg['header']
  mappings=fg['mappings']
  cD=fg['contractionStarters']
  aQ=fg['longestInitialSubstring']
  subtypes=fg['subtypes']
  file.close()
  aR=fi.get('collation_subtype')
  for key,aS in subtypes.items():
   eS=int(key,16)
   fi.set(eS,aR,aS)
  root=CollationNode()
  for string,eu in mappings.items():
   dz=string.split()[0]
   if not fh.l(int(dz,16)):
    continue
   if dz in cD:
    ei=cH(string)
    eN=root
    for fb in ei:
     eN=eN.cA(fb)
    assert eN.dY==0,'expected contractions to be unqiue'
    eN.dY=cC(eu)
  ez=root.aO()
  de=0
  for string,eu in mappings.items():
   de=max(len(eu),de)
   ei=cH(string)
   dz=string.split()[0]
   if dz in cD:
    eN=root.cA(ei[0])
    collation.set(ei[0],dd,eN.cz|cw)
   else:
    assert len(ei)==1,'expected a single character mapping'
    if len(eu)==1:
     collation.set(ei[0],dd,eu[0]|db)
    else:
     collation.set(ei[0],dd,cC(eu)|cv)
  fg=cL(collation,'CollationChararacterData','uni_get_collation_data')
  size=fg.size
  source=fg.source
  source+='const uint32_t unicorn_collation_mappings[] = {\n'
  for dR,en in enumerate(dO):
   if dR%4==0:
    source+='\n    '
   source+='0x{:08X}u, '.format(en)
   size+=4
  source+='};\n\n'
  source+='const struct CollationNode unicorn_collation_mappings_trie[] = {\n'
  for eN in ez:
   assert len(eN.eF)<=255
   ep=len(eN.eF)<<24|eN.ev
   aT=eN.dY
   aU=eN.cy
   source+=f'    {{ {ep}u, {aT}, {aU} }},\n'
   size+=8
  source+='};\n\n'
  header=fg.header
  header+=aP
  header+='#define UNICORN_MAX_COLLATION {0}\n'.format(de+1)
  header+='#define INLINE_CE_FLAG {0}u\n'.format(db)
  header+='#define IN_WEIGHT_TABLE_FLAG {0}u\n'.format(cv)
  header+='#define IN_TRIE_FLAG {0}u\n'.format(cw)
  header+='#define CONTINUATION_FLAG {0}u\n'.format(cx)
  header+='#define LONGEST_INITIAL_SUBSTRING {0}\n'.format(aQ)
  header+='#define UNICORN_IN_COLLATION_TABLE(NODE) ((NODE)->collation_mappings_offset > (uint16_t)0)\n'
  header+='#define GET_NODE_CODE_POINT(NODE) ((NODE)->codepoint_and_childcount & 0x1FFFFFu)\n'
  header+='#define GET_NODE_CHILD_COUNT(NODE) ((NODE)->codepoint_and_childcount >> 24u)\n'
  header+='struct CollationNode {\n'
  header+='    uint32_t codepoint_and_childcount;\n'
  header+='    uint16_t collation_mappings_offset;\n'
  header+='    uint16_t child_offset;\n'
  header+='};\n'
  header+='extern const struct CollationNode unicorn_collation_mappings_trie[{0}];\n'.format(len(ez))
  header+='extern const uint32_t unicorn_collation_mappings[{0}];\n'.format(len(dO))
  fd='#define UNICORN_FEATURE_COLLATION\n'
  return fe(source,header,fd,size)
from typing import Set,Type
import zipfile
import json
eA=0
class df(Feature):
 def cT(self,ff,eg,dr):
  gcb=ff.open('segmentation.json')
  fg=json.loads(gcb.read())
  header=fg['header']
  gcb.close()
  header+='#define MAX_BREAK_STATES {0}\n'.format(eA)
  fd='#define UNICORN_FEATURE_SEGMENTATION\n'
  return fe(header=header,fd=fd)
class aY(Feature):
 @staticmethod
 def eO():
  return set([df])
 def eP(self,fi):
  fi.eU('gcb',0,eV.eI)
  fi.eU('incb',0,eV.eI)
 def eX(self,ff,fi,_):
  gcb=ff.open('gcb.json')
  fg=json.loads(gcb.read())
  header=fg['header']
  source=fg['source']
  size=fg['size']
  gcb.close()
  global eA
  eA=max(int(fg['states']),eA)
  aW=fi.get('gcb')
  for eM in fg['gcb']:
   fi.set(eM[0],aW,eM[1])
  aX=fi.get('incb')
  for eM in fg['incb']:
   fi.set(eM[0],aX,eM[1])
  fd='#define UNICORN_FEATURE_GCB\n'
  return fe(source,header,fd,size)
class co(Feature):
 @staticmethod
 def eO():
  return set([df])
 def eP(self,fi):
  fi.eU('wb',0,eV.eI)
  fi.eU('wbx',0,eV.eI)
 def eX(self,ff,fi,_):
  wb=ff.open('wb.json')
  fg=json.loads(wb.read())
  header=fg['header']
  source=fg['source']
  size=fg['size']
  wb.close()
  global eA
  eA=max(int(fg['states']),eA)
  dg=fi.get('wb')
  for eM in fg['wb']:
   fi.set(eM[0],dg,eM[1])
  aZ=fi.get('wbx')
  for eM in fg['wbx']:
   fi.set(eM[0],aZ,eM[1])
  fd='#define UNICORN_FEATURE_WB\n'
  return fe(source,header,fd,size)
class ba(Feature):
 @staticmethod
 def eO():
  return set([df])
 def eP(self,fi):
  fi.eU('sb',0,eV.eI)
 def eX(self,ff,fi,_):
  wb=ff.open('sb.json')
  fg=json.loads(wb.read())
  header=fg['header']
  source=fg['source']
  size=fg['size']
  wb.close()
  global eA
  eA=max(int(fg['states']),eA)
  dg=fi.get('sb')
  for eM in fg['sb']:
   fi.set(eM[0],dg,eM[1])
  fd='#define UNICORN_FEATURE_SB\n'
  return fe(source,header,fd,size)
import zipfile
class cq(Feature):
 def eX(self,ff,fi,fh):
  fd='#define UNICORN_FEATURE_ENCODING_UTF8\n'
  return fe(fd=fd)
class bb(Feature):
 def eX(self,ff,fi,fh):
  fd='#define UNICORN_FEATURE_ENCODING_UTF16\n'
  return fe(fd=fd)
class bc(Feature):
 def eX(self,ff,fi,fh):
  fd='#define UNICORN_FEATURE_ENCODING_UTF32\n'
  return fe(fd=fd)
from typing import List,Set,Tuple,Type
import sys
import os
import argparse
import zipfile
class dh(argparse.Namespace):
 def __init__(self):
  self.config_file='features.json'
  self.output_dir=''
  self.verbose=False
def di(s):
 return '\n'.join((cE for cE in s.splitlines() if cE.strip()))
def be(args,ff):
 header=''
 source=''
 fd=''
 eZ=set()
 fh=parse(args.config_file,ff)
 fd+='#include <stdint.h>\n'
 if fh.endian==dF.cM:
  fd+='#define UNICORN_BIG_ENDIAN\n'
 else:
  fd+='#define UNICORN_LITTLE_ENDIAN\n'
 fd+='#define UNICORN_STACK_BUFFER_SIZE {0}\n'.format(fh.bX)
 fd+='typedef {0} unichar;\n'.format(fh.cP)
 if fh.bW:
  fd+='#define UNICORN_HAVE_C_MEMORY_ROUTINES\n'
 header+='#include "unicorn.h"\n'
 dj=b.split('.')
 header+='#define UNICODE_VERSION_MAJOR {0}\n'.format(dj[0])
 header+='#define UNICODE_VERSION_MINOR {0}\n'.format(dj[1])
 header+='#define UNICODE_VERSION_PATCH {0}\n'.format(dj[2])
 if fh.optimize==er.el:
  header+='#define UNICORN_OPTIMIZE_FOR_SPEED // cppcheck-suppress misra-c2012-2.5\n'
 else:
  header+='#define UNICORN_OPTIMIZE_FOR_SIZE\n'
 if fh.algorithms.dU&ed.bq:
  eZ.add(cn)
 if fh.algorithms.dU&ed.br:
  eZ.add(at)
 if fh.algorithms.dU&ed.bs:
  eZ.add(au)
 if fh.eW&eY.bL:
  eZ.add(W)
 if fh.eW&eY.bB:
  eZ.add(Y)
 if fh.eW&eY.bJ:
  eZ.add(Z)
 if fh.eW&eY.bT:
  eZ.add(aa)
 if fh.eW&eY.bH:
  eZ.add(ab)
 if fh.eW&eY.bU:
  eZ.add(ac)
 if fh.eW&eY.bK:
  eZ.add(ad)
 if fh.eW&eY.bD:
  eZ.add(ae)
 if fh.eW&eY.bE:
  eZ.add(af)
 if fh.eW&eY.bF:
  eZ.add(ag)
 if fh.eW&eY.bI:
  eZ.add(ah)
 if fh.eW&eY.bN:
  eZ.add(ai)
 if fh.eW&eY.bS:
  eZ.add(aj)
 if fh.eW&eY.bR:
  eZ.add(ak)
 if fh.algorithms.compression:
  eZ.add(aM)
 if fh.algorithms.segmentation&ef.by:
  eZ.add(aY)
 if fh.algorithms.segmentation&ef.bz:
  eZ.add(co)
 if fh.algorithms.segmentation&ef.bA:
  eZ.add(ba)
 if fh.algorithms.normalization&ec.cN:
  eZ.add(aL)
 if fh.algorithms.normalization&ec.cO:
  eZ.add(ds)
 if fh.algorithms.bV:
  if fh.algorithms.normalization&ec.cN:
   eZ.add(aC)
  if fh.algorithms.normalization&ec.cO:
   eZ.add(aE)
 if fh.algorithms.collation:
  eZ.add(aV)
 if fh.algorithms.dn&dG.bt:
  eZ.add(cp)
 if fh.algorithms.dn&dG.bu:
  eZ.add(az)
 if fh.eW&eY.bG:
  eZ.add(am)
 if fh.eW&eY.bC:
  eZ.add(dM)
 if fh.eW&eY.bM:
  eZ.add(ao)
 if fh.eW&eY.bO:
  eZ.add(ch)
 if fh.eW&eY.bP:
  eZ.add(cj)
 if fh.eW&eY.bQ:
  eZ.add(cl)
 if fh.dV&ee.bv:
  eZ.add(cq)
 if fh.dV&ee.bw:
  eZ.add(bb)
 if fh.dV&ee.bx:
  eZ.add(bc)
 while True:
  dA=eZ.copy()
  for dk in eZ:
   dA=dA.union(dk.eO())
  if eZ==dA:
   break
  eZ=dA
 bd=sorted(list(eZ),key=lambda ep:ep.__class__.__name__)
 fi=fc()
 size=0
 dB=[]
 for dk in bd:
  eH=dk()
  eH.eP(fi)
  dB.append(eH)
 for eH in dB:
  fg=eH.eX(ff,fi,fh)
  source+=fg.source+'\n'
  header+=fg.header+'\n'
  fd+=fg.fd
  size+=fg.size
  eH.dq+=fg.size
 for eH in dB:
  fg=eH.cT(ff,fi,fh)
  source+=fg.source+'\n'
  header+=fg.header+'\n'
  fd+=fg.fd
  size+=fg.size
  eH.dq+=fg.size
 fg=cL(fi,'CodepointData','get_codepoint_data')
 source+=fg.source
 header+=fg.header
 size+=fg.size
 if args.verbose:
  for eH in dB:
   if eH.dq>0:
    print('Added: {} ({:.2f} kB)'.format(eH.__class__.__name__,eH.dq/1024))
   else:
    print('Added: {}'.format(eH.__class__.__name__))
  print('Character table size: ({:.2f} kB)'.format(fg.size/1024))
  print('Total size: {:.2f} kB'.format(size/1024))
 source=di(source)
 header=di(header)
 fd=di(fd)
 source+='\n'
 header+='\n'
 fd+='\n'
 return (header,source,fd)
def main(args):
 ff=zipfile.ZipFile('unicorn.bin','r')
 bf,bg,bh=be(args,ff)
 file=ff.open('code.c')
 bi=file.read().decode('utf-8-sig')
 file.close()
 file=ff.open('code.h')
 bj=file.read().decode('utf-8-sig')
 file.close()
 copyright='/*\n *  Unicorn: Embeddable Unicode algorithms software library.\n *  Copyright (c) 2025 Railgun Labs, LLC\n *\n *  This file is part of Unicorn, distributed under a non-commercial use software\n *  license. For the full terms see the included LICENSE file. If you did not\n *  receive a LICENSE file or you would like to purchase a commercial license,\n *  contact us at <https://RailgunLabs.com/contact/>.\n */\n\n// The Unicorn source code has been amalgamated into a monolithic source\n// and header file. As part of the amalgamation process all code comments\n// and extraneous white space have been removed.\n//\n// The amalgamation is intended for consumption, not development. The\n// unamalgamated source code can be obtained by purchasing a license\n// from Railgun Labs at https://RailgunLabs.com/unicorn/license.\n\n'
 filename=os.path.join(args.output_dir,'unicorn.c')
 fp=open(filename,'w',encoding='utf-8',newline='\n')
 fp.write(copyright)
 fp.write(bf)
 fp.write(bi)
 fp.write('#if !defined(__cppcheck__)\n')
 fp.write(bg)
 fp.write('#endif\n')
 fp.close()
 print('writing:',os.path.realpath(filename))
 filename=os.path.join(args.output_dir,'unicorn.h')
 fp=open(filename,'w',encoding='utf-8',newline='\n')
 fp.write(copyright)
 fp.write('#ifndef UNICORN_H\n')
 fp.write('#define UNICORN_H\n')
 fp.write(bh)
 fp.write(bj)
 fp.write('#endif\n')
 fp.close()
 print('writing:',os.path.realpath(filename))
 return 0
if __name__=='__main__':
 if isinstance(sys.version_info,tuple):
  cF=sys.version_info[0]
  cG=sys.version_info[1]
 else:
  cF=sys.version_info.major
  cG=sys.version_info.minor
 if cF<3 or cG<9:
  raise Exception('This script requires Python 3.9 or newer')
 dC=argparse.ArgumentParser(description='Build Unicorn source and header.')
 dC.add_argument('--config',dest='config_file',action='store',help='path to configuration file')
 dC.add_argument('--output',dest='output_dir',action='store',help='path to write generated C source files')
 dC.add_argument('--verbose',dest='verbose',action='store_true',help='report added features and their size contributions')
 args=dh()
 dC.parse_args(namespace=args)
 sys.exit(main(args))